<?php
declare(strict_types=1);

namespace App\Service\Im;

use App\Constants\ContextKey;
use App\Constants\ErrorCode;
use App\Dao\AdminUserDao;
use App\Dao\CooperativeUserDao;
use App\Dao\ImChatDao;
use App\Dao\ImChatMessageLogDao;
use App\Dao\TaskDao;
use App\Dao\UserDao;
use App\Dao\UserEmployerDao;
use App\Exception\BusinessException;
use App\Model\Imchat;
use App\Model\ImchatMessageLog;
use App\Service\Client\BaseService;
use App\Utils\Redis;
use App\Utils\Upload;
use Hyperf\Database\Model\Builder;
use Hyperf\Database\Model\Model;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Utils\Context;
use App\Constants\ImChat as Constants;
use Psr\Container\ContainerInterface;
use App\Constants\Redis\Im as ImRedisConstants;

class ImChatService extends BaseService
{
    /**
     * @var string
     */
    private $prefix = '_';

    /**
     * 聊天记录
     * @Inject()
     * @var ImChatDao
     */
    private $imchatDao;

    /**
     * 聊天信息记录
     * @Inject()
     * @var ImChatMessageLogDao
     */
    protected $ImChatMessageLogDao;

    /**
     * 普通用户
     * @Inject()
     * @var UserDao
     */
    protected $userDao;

    /**
     * 合作商
     * @Inject()
     * @var CooperativeUserDao
     */
    protected $cooperativeUserDao;


    /**
     * 母公司后台
     * @Inject()
     * @var AdminUserDao
     */
    protected $adminUserDao;

    /**
     * 悬赏主信息
     * @Inject()
     * @var UserEmployerDao
     */
    protected $employer;

    /**
     * 任务
     * @Inject()
     * @var TaskDao
     */
    protected $taskDao;

    /**
     * @var \Hyperf\Redis\RedisProxy|\Redis|null
     */
    protected $redis;

    public function __construct(ContainerInterface $container)
    {
        $this->redis = di(Redis::class);
    }

    public function getCurrentUserInfo()
    {
        return Context::get(ContextKey::USE_IM_USER);
    }


    /**
     * 生成otp访问key
     * @return false|string
     */
    public function goEasyOTP()
    {
        $key = config('goeasy.secret_key');
        list($t1, $t2) = explode(' ', microtime());
        $text = (float)sprintf('%.0f', (floatval($t1) + floatval($t2)) * 1000);
        $text = "000" . $text;
        //发送用户Id
        $userInfo = $this->getCurrentUserInfo();
        $key_secret['user_id'] = $userInfo->prefix . $userInfo->id;
        $key_secret['otp_key'] = openssl_encrypt($text, 'AES-128-ECB', $key, 2, '');
        $key_secret['client_key'] = config('goeasy.client_key');
        return $key_secret;
    }


    /**
     * 创建会话
     * @param $param
     * @return Imchat|Builder|Model|object
     */
    public function CreateImChat($param)
    {
        //接收用户Id
        $receiveUser = $this->checkReceive($param['receive_platform'], $param['receive_id']);
        if (!$receiveUser) {
            throw new BusinessException(ErrorCode::RECEIVE_USER_NOT_FOUND);
        }

        //发送用户Id
        $userInfo = $this->getCurrentUserInfo();
        $sendUser = $userInfo->prefix . $userInfo->id;
        if ($sendUser != $param['user_id']) {
            throw new BusinessException(ErrorCode::USER_ID_NOT_FOUND);
        }

        //保存会话记录
        $existChat = $this->imchatDao->first(['send_user' => $sendUser, 'receive_user' => $receiveUser]);

        if (!$existChat) {
            //保存新的聊天会话
            $imchat = new Imchat();
            $imchat->send_user = $sendUser;
            $imchat->receive_user = $receiveUser;
            $imchat->cooperative_employer_user = $userInfo->cooperative_employer_user ?? 0;
            $imchat->save();
            $arr = explode($this->prefix, $receiveUser);
            $user = $this->chatUserInfo($arr[0])->first(['id' => $arr[1]]);
            $imchat['username'] = $user->username ?? $user->nickname;
            $imchat['avatar'] = $user->avatar ?? '';
            unset($imchat['updated_at']);
            unset($imchat['deleted_at']);
            return $imchat;
        } else {
            $existChat->updated_at = date('Y-m-d H:i:s', time());
            $existChat->deleted_at = NULL;
            $existChat->save();
            $arr = explode($this->prefix, $existChat->receive_user);
            $user = $this->chatUserInfo($arr[0])->first(['id' => $arr[1]]);
            $existChat['username'] = $user->username ?? $user->nickname;
            $existChat['avatar'] = $user->avatar ?? '';
            unset($existChat['updated_at']);
            unset($existChat['deleted_at']);
            return $existChat;
        }

    }


    /**
     * 检查接收方是否存在
     * @param $receive
     * @param $receive_id
     * @return bool|string
     */
    public function checkReceive($receive, $receive_id)
    {
        $chatUser = $this->chatUserInfo($receive)->first(['id' => $receive_id]);
        if (!$chatUser) {
            return false;
        }
        return $receive . $this->prefix . $receive_id;
    }


    /**
     * 获取会话列表
     * @return array
     */
    public function messageList()
    {
        $userInfo = $this->getCurrentUserInfo();
        $send_user = $userInfo->prefix . $userInfo->id;
        $where = ['send_user' => $send_user, 'deleted_at' => NULL];
        if ($userInfo->cooperative_employer_user){
            $where['cooperative_employer_user'] = $userInfo->cooperative_employer_user;
        }
        $list = $this->imchatDao->paginate($where, 20, ['id', 'receive_user']);
        $user = array();
        foreach ($list as $key => $val) {
            $arr = explode($this->prefix, $val->receive_user);
            $chatUser = $this->chatUserInfo($arr[0])->first(['id' => $arr[1]]);
            $user[$key]['id'] = $val->id;
            $user[$key]['username'] = $chatUser->username ?? $chatUser->nickname;
            $user[$key]['avatar'] = $chatUser->avatar ?? '';
            $user[$key]['send_user'] = $send_user;
            $user[$key]['receive_user'] = $val->receive_user;
            $msg = $this->redis->hGet(ImRedisConstants::IM_LAST_MESSAGE, (string)$val->id);
            $user[$key]['message'] = $msg ?? '';
            /** @var ImchatMessageLog|null $lastRow */
            $lastRow = !empty($msg) ? $this->ImChatMessageLogDao->getLastRowByImchatID($val->id) : null;
            $user[$key]['last_time'] = $lastRow->created_at ?? null;
            $user[$key]['last_history_id'] = isset($lastRow->id) ? ($lastRow->id + 1) : null;
        }
        return $user;
    }

    /**
     * @param $type
     * @return AdminUserDao|CooperativeUserDao|UserDao
     */
    public function chatUserInfo($type)
    {
        switch($type) {
            case Constants::ADMIN:
                return $this->adminUserDao;
                break;
            case Constants::PARTNER:
                return $this->cooperativeUserDao;
                break;
            case Constants::USER:
                return $this->userDao;
                break;
        }
        throw new BusinessException(ErrorCode::MODEL_NOT_FOUNT);
    }


    /**
     * 删除聊天记录
     * @param int $id
     * @return bool
     */
    public function delMessage(int $id): bool
    {
        $userInfo = $this->getCurrentUserInfo();
        $send_user = $userInfo->prefix . $userInfo->id;
        /** @var Imchat $existChat */
        $existChat = $this->imchatDao->first(['id' => $id, 'send_user' => $send_user]);
        if (!$existChat) {
            throw new BusinessException(ErrorCode::CAHT_LOG_NOT_FOUND);
        }

        $existChat->deleted_at = date('Y-m-d H:i:s', time());
        //清除聊天信息

        return $existChat->save();
    }



    /**
     * 保存聊天内容
     * @param array $data
     * @return bool|int
     */
    public function saveLastMessage(array $data)
    {
        $userInfo = $this->getCurrentUserInfo();
        $send_user = $userInfo->prefix . $userInfo->id;
        /** @var  Imchat $channel */
        $channel = $this->imchatDao->first(['send_user' => $send_user, 'receive_user' => $data['receive_user']], ['id']);
        if (!$channel) {
            throw new BusinessException(ErrorCode::CAHT_LOG_NOT_FOUND);
        }
        $msg = json_decode($data['message'], true);
        if (is_array($msg)) {
            //保存到数据表
            $messageLog = new ImchatMessageLog();
            $messageLog->imchat_id = $channel->id;
            $messageLog->message = serialize($msg);
            $messageLog->send_user = $send_user;
            $messageLog->receive_user = $data['receive_user'];
            $messageLog->cooperative_employer_user = $userInfo->cooperative_employer_user ?? 0;
            $messageLog->save();

            if ($msg['type'] == 'image') {
                $newMsg = '[图片]';
            } else {
                $newMsg = $msg['payload']['text'] ?? '';
            }
            //消息保存到redis
            $this->redis->hSet(ImRedisConstants::IM_LAST_MESSAGE, (string)$channel->id, $newMsg);
            return $msg;
        } else {
            return false;
        }
    }

    /**
     * 获取历史消息
     * @param $data
     * @return mixed
     */
    public function messageLog($data)
    {
        $userInfo = $this->getCurrentUserInfo();
        $send_user = $userInfo->prefix . $userInfo->id;
        $data['send_user'] = $send_user;
        if ($userInfo->cooperative_employer_user){
            $data['cooperative_employer_user'] = $userInfo->cooperative_employer_user;
        }
        /** @var ImchatMessageLog $message */
        $message = $this->ImChatMessageLogDao->getMessageLog($data)->toArray();
        $sendUser = $this->getUserData($send_user);
        $receiveUser = $this->getUserData($data['receive_user']);
        $message_log = [];
        $updateId = [];
        foreach ($message as $key => $val) {
            if (!empty($val['message'])) {
                $msg = unserialize($val['message']);
                if ($val['send_user'] == $send_user) {
                    $avatar = isset($sendUser->avatar) ? $sendUser->avatar : '';
                    $user_name = isset($sendUser->nickname) ? $sendUser->nickname : $sendUser->username;
                } else {
                    $avatar = isset($receiveUser->avatar) ? $receiveUser->avatar : '';
                    $user_name = isset($receiveUser->nickname) ? $receiveUser->nickname : $receiveUser->username;
                }
                $message_log[$key]['avatar'] = $avatar;
                $message_log[$key]['user_name'] = $user_name;
                $message_log[$key]['message'] = $msg;
                $message_log[$key]['time'] = $val['created_at'];
                $last_history_id = $val['id']; // 设置最后历史ID
            }

            //如果是未读标记为已读
            if ($val['status'] == 0) {
                array_push($updateId, $val['id']);
            }
        }

        // 判断查询的数据如果小于查询页数，说明已经没有历史消息了
        $prePage = $data['per_page'] ?? 30;
        $total = count($message_log);
        if ($total < $prePage) {
            $last_history_id = null;
        }

        //更新已读状态
        $this->ImChatMessageLogDao->updateStatus($updateId, 1);

        $list['data'] = array_reverse($message_log);
        $list['total'] = $total;
        $list['per_page'] = intval($prePage);
        $list['last_history_id'] = $last_history_id ?? null;
        return $list;
    }

    /**
     * 用户信息
     * @param $uid
     * @param array $field
     * @return Builder|Model|object|string|null
     */
    public function getUserData($uid,$field = [])
    {
        $user = explode('_',$uid);
        if (!is_array($user)){
            return '';
        }
        return $this->chatUserInfo($user[0])->first(['id'=>$user[1]],$field);
    }

    /**
     * 获取客服列表
     * @return array
     */
    public function getCustomerList()
    {
        $user = $this->getCurrentUserInfo();
        $result = $this->cooperativeUserDao->getCustomerList(['cooperative_id' => $user->cooperative_id]);
        foreach ($result as $key => $val) {
            $result[$key]['id'] = 'cooperative_' . $val['id'];
        }
        return $result;
    }

    /**
     * 聊天框用户信息
     * @param $user
     * @return Builder|Model|string|null
     */
    public function UserData($user)
    {
        $param = explode($this->prefix,$user);
        if ($param[0] == Constants::USER){
            $field = ['id','nickname','phone','avatar','level','credit_point','commission','done_task_exec_count','withdraw_gold','is_employer','created_at as regist_time'];
            $info = $this->getUserData($user,$field);
            if (isset($info->is_employer) && $info->is_employer > 0){
                //获取悬赏主信息
                $employer = $this->employer->first(['user_id'=>$info->id],['credit_point','balance']);
                $employer->task_count = $this->taskDao->where(['employer_id'=>$info->id])->count();
                $info['employer'] = $employer;
            }

            return $info;
        }

        throw new BusinessException(ErrorCode::RECEIVE_USER_NOT_USER);
    }

}